package com.it.smartoldb.service;

import com.it.smartoldb.entity.Appointment;
import com.it.smartoldb.repository.AppointmentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 预约服务类
 */
@Service
@Transactional
public class AppointmentService {

    @Autowired
    private AppointmentRepository appointmentRepository;

    /**
     * 创建预约
     */
    public Appointment createAppointment(Appointment appointment) {
        // 检查时间冲突
        if (appointment.getStaffId() != null) {
            checkTimeConflict(appointment);
        }
        
        appointment.setStatus(Appointment.AppointmentStatus.PENDING);
        return appointmentRepository.save(appointment);
    }

    /**
     * 更新预约
     */
    public Appointment updateAppointment(Long id, Appointment appointment) {
        Optional<Appointment> existing = appointmentRepository.findById(id);
        if (!existing.isPresent()) {
            throw new RuntimeException("预约记录不存在");
        }
        
        Appointment existingAppointment = existing.get();
        
        // 如果更新了护理人员或时间，检查冲突
        if (!existingAppointment.getStaffId().equals(appointment.getStaffId()) ||
            !existingAppointment.getAppointmentTime().equals(appointment.getAppointmentTime()) ||
            !existingAppointment.getEndTime().equals(appointment.getEndTime())) {
            checkTimeConflict(appointment);
        }
        
        // 更新字段
        existingAppointment.setElderlyId(appointment.getElderlyId());
        existingAppointment.setStaffId(appointment.getStaffId());
        existingAppointment.setServiceType(appointment.getServiceType());
        existingAppointment.setAppointmentTime(appointment.getAppointmentTime());
        existingAppointment.setEndTime(appointment.getEndTime());
        existingAppointment.setFee(appointment.getFee());
        existingAppointment.setBookerName(appointment.getBookerName());
        existingAppointment.setBookerPhone(appointment.getBookerPhone());
        existingAppointment.setNotes(appointment.getNotes());
        existingAppointment.setServiceAddress(appointment.getServiceAddress());
        existingAppointment.setPriority(appointment.getPriority());
        
        return appointmentRepository.save(existingAppointment);
    }

    /**
     * 删除预约
     */
    public void deleteAppointment(Long id) {
        if (!appointmentRepository.existsById(id)) {
            throw new RuntimeException("预约记录不存在");
        }
        appointmentRepository.deleteById(id);
    }

    /**
     * 根据ID查找预约
     */
    public Optional<Appointment> findById(Long id) {
        return appointmentRepository.findById(id);
    }

    /**
     * 分页查询老人的预约
     */
    public Page<Appointment> findByElderlyId(Long elderlyId, Pageable pageable) {
        return appointmentRepository.findByElderlyIdOrderByAppointmentTimeDesc(elderlyId, pageable);
    }

    /**
     * 分页查询护理人员的预约
     */
    public Page<Appointment> findByStaffId(Long staffId, Pageable pageable) {
        return appointmentRepository.findByStaffIdOrderByAppointmentTimeDesc(staffId, pageable);
    }

    /**
     * 多条件分页查询
     */
    public Page<Appointment> findAppointmentsWithFilters(Long elderlyId, Long staffId,
                                                        Appointment.AppointmentStatus status,
                                                        String serviceType, Pageable pageable) {
        return appointmentRepository.findAppointmentsWithFilters(elderlyId, staffId, status, serviceType, pageable);
    }

    /**
     * 确认预约
     */
    public Appointment confirmAppointment(Long id) {
        Optional<Appointment> appointment = appointmentRepository.findById(id);
        if (!appointment.isPresent()) {
            throw new RuntimeException("预约记录不存在");
        }
        
        Appointment app = appointment.get();
        if (app.getStatus() != Appointment.AppointmentStatus.PENDING) {
            throw new RuntimeException("只能确认待确认状态的预约");
        }
        
        app.setStatus(Appointment.AppointmentStatus.CONFIRMED);
        return appointmentRepository.save(app);
    }

    /**
     * 开始预约服务
     */
    public Appointment startAppointment(Long id) {
        Optional<Appointment> appointment = appointmentRepository.findById(id);
        if (!appointment.isPresent()) {
            throw new RuntimeException("预约记录不存在");
        }
        
        Appointment app = appointment.get();
        if (app.getStatus() != Appointment.AppointmentStatus.CONFIRMED) {
            throw new RuntimeException("只能开始已确认的预约");
        }
        
        app.setStatus(Appointment.AppointmentStatus.IN_PROGRESS);
        return appointmentRepository.save(app);
    }

    /**
     * 完成预约
     */
    public Appointment completeAppointment(Long id) {
        Optional<Appointment> appointment = appointmentRepository.findById(id);
        if (!appointment.isPresent()) {
            throw new RuntimeException("预约记录不存在");
        }
        
        Appointment app = appointment.get();
        if (app.getStatus() != Appointment.AppointmentStatus.IN_PROGRESS) {
            throw new RuntimeException("只能完成进行中的预约");
        }
        
        app.setStatus(Appointment.AppointmentStatus.COMPLETED);
        return appointmentRepository.save(app);
    }

    /**
     * 取消预约
     */
    public Appointment cancelAppointment(Long id, String reason) {
        Optional<Appointment> appointment = appointmentRepository.findById(id);
        if (!appointment.isPresent()) {
            throw new RuntimeException("预约记录不存在");
        }
        
        Appointment app = appointment.get();
        if (app.getStatus() == Appointment.AppointmentStatus.COMPLETED ||
            app.getStatus() == Appointment.AppointmentStatus.CANCELLED) {
            throw new RuntimeException("已完成或已取消的预约不能再次取消");
        }
        
        app.setStatus(Appointment.AppointmentStatus.CANCELLED);
        app.setCancelReason(reason);
        return appointmentRepository.save(app);
    }

    /**
     * 获取预约统计信息
     */
    public Map<String, Object> getAppointmentStatistics() {
        List<Object[]> statusStats = appointmentRepository.countByStatus();
        List<Object[]> serviceTypeStats = appointmentRepository.countByServiceType();
        
        Map<String, Long> statusMap = statusStats.stream()
                .collect(java.util.stream.Collectors.toMap(
                    result -> ((Appointment.AppointmentStatus) result[0]).getDescription(),
                    result -> (Long) result[1]
                ));
        
        Map<String, Long> serviceTypeMap = serviceTypeStats.stream()
                .collect(java.util.stream.Collectors.toMap(
                    result -> (String) result[0],
                    result -> (Long) result[1]
                ));
        
        return Map.of(
                "statusStats", statusMap,
                "serviceTypeStats", serviceTypeMap,
                "totalCount", appointmentRepository.count()
        );
    }

    /**
     * 获取即将到来的预约
     */
    public List<Appointment> getUpcomingAppointments() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime tomorrow = now.plusDays(1);
        return appointmentRepository.findUpcomingAppointments(now, tomorrow);
    }

    /**
     * 获取待确认的预约
     */
    public List<Appointment> getPendingAppointments() {
        return appointmentRepository.findByStatusOrderByCreatedAtAsc(Appointment.AppointmentStatus.PENDING);
    }

    /**
     * 获取预约总数
     */
    public long getTotalCount() {
        return appointmentRepository.count();
    }

    /**
     * 检查时间冲突
     */
    private void checkTimeConflict(Appointment appointment) {
        if (appointment.getStaffId() == null || appointment.getAppointmentTime() == null) {
            return;
        }
        
        LocalDateTime startTime = appointment.getAppointmentTime();
        LocalDateTime endTime = appointment.getEndTime();
        if (endTime == null) {
            // 默认预约时长2小时
            endTime = startTime.plusHours(2);
        }
        
        List<Appointment> conflicts = appointmentRepository.findConflictingAppointments(
                appointment.getStaffId(), startTime, endTime);
        
        if (!conflicts.isEmpty()) {
            throw new RuntimeException("护理人员在该时间段已有其他预约，请选择其他时间");
        }
    }
} 